Some scala basics

A few very simple characteristics of the Scala language. No Spark specifics yet.

Mostly taken from A short primer on Scala. See also additional documentation in Scala overviews and the Scala cheatsheet

In terms of general syntax, Scala is quite similar to Java. One difference is that it is less picky with semicolons: they are optional at the end of the line. Also, Scala uses the "everything is an object" motto. All language constructs (primitive types & complex types, but also functions) are objects that can be passed around; this eases functional programming.


In [ ]:
// Which version of Scala?
scala.util.Properties.versionNumberString

Variables

Mutable and immutable values. Type inference


In [ ]:
// A mutable variable, defined with explicit type specification
var a: Int = 5
a = a + 1
println(a)

// Inmutable variables
val v1: Double = 6.2
val v2: String = "Hi!"
println( v1, v2)

// Same as before, but now we use type inference
val v1b = 6.2
val v2b = "Hi!"
println( v1b, v2b)
println( v1b.getClass, v2b.getClass )

Functions


In [ ]:
/* Define a function that takes an integer and returns an integer. 
   This one is a one-liner, otherwise we would use braces. 
   Also, we do not need a return statement since we are returning the last (and only) expression */
def fact(n: Int): Int =  if (n == 0) 1 else n*fact(n-1)

In [ ]:
// Use the function
fact(10)

Anonymous functions

Functions can also be defined on the fly. Anonymous functions can be assigned to a variable so that we can call it later


In [ ]:
// A function, with type specification
// (if the context was clear, we could use type inference)
val cube = (x : Int)  => x*x*x

cube(7)

In [ ]:
// Same thing, but using explicit return type specification
val cube: Int => Double = x => x*x*x

cube(5)

In [ ]:
// If the function is more complex, we use a brace block
val cubeOrSquare = (x: Int) => { if( x < 10 )
                                    x*x*x
                                 else
                                    x*x }
                                    
print( cubeOrSquare(7), cubeOrSquare(11) )

There is also a shorthand used in which we use the underscore (_) as a placeholder for anonymous arguments, and we skip the argument list. See below

Higher order functions

These are functions that take another function as a paramete and/or return a function


In [ ]:
// A function that takes another function and a value, and applies the function to the square of the value 
def applySquared( func: Int => Int, value: Int) = func( value*value )

// Prepare the function we will pass
val minusOne = (x : Int) => x - 1

// This should compute x^2 - 1
print( applySquared( minusOne, 3 ) )

// We can also pass directly an anonymous function. This is x^2 + 2
applySquared( _ + 2, 6 )

Classes


In [ ]:
/* Define a class */
class Point( xc: Int, yc: Int ) {
    var x: Int = xc
    var y: Int = yc
    def move(dx: Int, dy: Int) {
        x = x + dx
        y = y + dy
    }
    override def toString(): String = "(" + x + ", " + y + ")";
}

/* Create an instance, and operate with it */
val p = new Point( 10, 11 )
p.move( 2, -1 )
println( p )

Collections

Scala predefines a good set of collections (similar to the ones existing in other programming languages) ready to be used. See Scala collections for documentation.

A list (ordered collection of items):


In [ ]:
var l = List( 1, 2, 3, 4, 5 )

In [ ]:
l.reverse

A set (unordered collection of items, with fast pertenence operations):


In [ ]:
var s = Set( "a", "b", "c", "d")

In [ ]:
s.contains( "c" )

In [ ]:
s & Set("a","c","f")

Ranges

Ranges are collections of numerical elements


In [ ]:
val r = Range(1,10)

r

There is also a special syntax to define ranges using to or until


In [ ]:
1 to 10

In [ ]:
// define a range with a fractional increment, and convert the result to Array
(1.0 until 10.0 by 0.5).toArray

Operations on collections

Scala collection classes define abstract methods that apply to their contents.

For instance, the map function is a higher order function, which takes a function as an argument and applies them to all elements in the collection:


In [ ]:
val numbers = List(1,2,3,4)

// We use here an anonymous function
numbers.map( x => 2 * x )

In [ ]:
// Same, but now with the shorthand using the underscore, which is interpreted as a reference to an anonymous argument
numbers.map( 2 * _ )

In [ ]:
// Another example
numbers.filter( _ <= 2 )

Another variant: the reduceLeft function applies a binary operation (two parameters) successively, until all elements in the collection have been consumed:


In [ ]:
numbers.reduceLeft( (a, b) => a + b )

In [ ]:
// Again, using the underscore shorthand (each underscore refers to one of the two parameters)
numbers.reduceLeft( _ + _ )

In [ ]: